function! SwapUp()
  if ( line( '.' ) > 1 )
    let cur_col = virtcol(".")
    if ( line( '.' ) == line( '$' ) )
      normal ddP
    else
      normal ddkP
    endif
    execute "normal " . cur_col . "|"
  endif
endfunction

function! SwapDown()
  if ( line( '.' ) < line( '$' ) )
    let cur_col = virtcol(".")
    normal ddp
    execute "normal " . cur_col . "|"
  endif
endfunction

function! MoveCursor(move, mode)
	if (a:move == 'h')
		if (a:mode == '0')
			normal 0
		elseif (a:mode =~ '^\^')
			if (a:mode == '^g')
				normal g^
			elseif (a:mode == '^n')
				normal ^
			endif
		endif
	elseif (a:move == 'e')
		if (a:mode =~ '^\$')
			if (a:mode == '$g')
				normal g$
			elseif (a:mode == '$n')
				normal $
			endif
		endif
	endif
endfunction

function! HomeKey()
	let oldmode = mode()
	let oldcol = col('.')
	call MoveCursor('h', '^n')
	let newcol = col('.')
	if (oldcol == newcol)
		if (&wrap != 1) || (newcol <= winwidth(0) - 20)
			call MoveCursor('h', '0')
			let lastcol = col('.')
			if (newcol == lastcol)
				if (newcol == oldcol)
					normal i
				else
					call MoveCursor('h', '^n')
				endif
			else
				call MoveCursor('h', '0')
			endif
		endif
	endif
endfunction

function! EndKey()
	call MoveCursor('e', '$g')
endfunction

function! StrMatchNo(haystack, needle)
	let LastMatch = match(a:haystack, a:needle)
	if LastMatch > -1
		let Result = 1
		while LastMatch > -1
			let LastMatch = match(a:haystack, a:needle, LastMatch+1)
			if LastMatch > -1
				let Result = Result + 1
			endif
		endwhile
	else
		let Result = 0
	endif
	return Result
endfunction

function! ConditionalExecute(action)
	if a:action == "write"
		if &modified == 1
			silent write
		endif
	elseif a:action == "quit"
		new
		execute "normal! \<C-w>\<C-w>"
		silent quit
	endif
endfunction

function! InsertBrace()
	if strpart(getline("."), col(".")-1, 1) != " "
		let s:seq = " "
	else
		let s:seq = ""
	endif
	let s:seq = s:seq . "{\<CR>}\<Left>\<CR>\<Up>\<Tab>"
	execute "normal a" . s:seq
endfunction

function! KeyMap(modifier, key, action, mode, target)
	if strlen(a:mode) > 0
		let s:mode = " <" . a:mode . "> "
	else
		let s:mode = " "
	endif
	if StrMatchNo(a:action, '<CR>') > 1 || a:action =~ 'e' || a:action !~ '<CR>$'
		let s:insert{"pre"} = " <Esc>"
		let s:insert{"post"} = "a"
	else
		let s:insert{"pre"} = " <C-o>"
		let s:insert{"post"} = ""
	endif
	if a:target =~ '_'
		let s:insert{"pre"} = " "
		let s:insert{"post"} = ""
	endif
	" modifier: <M> meta
	if a:modifier == "M"
		if a:target =~ 'n'
			execute "nnoremap" . s:mode . "<M-" . a:key . "> " . a:action
		endif
		if a:target =~ 'i'
			execute "inoremap" . s:mode . "<M-" . a:key . ">" . s:insert{"pre"} . a:action . s:insert{"post"}
		endif
		if a:target =~ 'v'
			execute "vnoremap" . s:mode . "<M-" . a:key . "> " . a:action
		endif
	" modifier: <C> control
	elseif a:modifier == "C"
		let s:key = substitute(a:key, '[<>]', '', 'g')
		if a:target =~ 'n'
			execute "nnoremap" . s:mode . "<C-" . s:key . "> " . a:action
		endif
		if a:target =~ 'i'
			execute "inoremap" . s:mode . "<C-" . s:key . ">" . s:insert{"pre"} . a:action . s:insert{"post"}
		endif
		if a:target =~ 'v'
			execute "vnoremap" . s:mode . "<C-" . s:key . "> " . a:action
		endif
	" modifier: <S> shift
	elseif a:modifier == "C"
		let s:key = substitute(a:key, '[<>]', '', 'g')
		if a:target =~ 'n'
			execute "nnoremap" . s:mode . "<S-" . s:key . "> " . a:action
		endif
		if a:target =~ 'i'
			execute "inoremap" . s:mode . "<S-" . s:key . ">" . s:insert{"pre"} . a:action . s:insert{"post"}
		endif
		if a:target =~ 'v'
			execute "vnoremap" . s:mode . "<S-" . s:key . "> " . a:action
		endif
	" modifier: none
	else
		if a:target =~ 'n'
			execute "nnoremap" . s:mode . a:key . " " . a:action
		endif
		if a:target =~ 'i'
			execute "inoremap" . s:mode . a:key . s:insert{"pre"} . a:action . s:insert{"post"}
		endif
		if a:target =~ 'v'
			execute "vnoremap" . s:mode . a:key . " " . a:action
		endif
	endif
endfunction

function! OpenFileUnderCursor()
	let FileName = expand("<cfile>")
	if (!filereadable(FileName))
		if (filereadable("./" . FileName))
			let FileName = "./" . FileName
		else
			let cpwd = substitute(getcwd(), '\([^/]\)$', '\1/', '')
			let fpwd = substitute(FileName, '^.\{-}\(/.*/\).*$', '\1', '')
			if (match(cpwd, fpwd . '$'))
				let FileName = substitute(FileName, '^.*/\(.*\)$', '\1', '')
			endif
		endif
	endif
	let OldPath = getcwd()
	silent cd %:p:h
	if (filereadable(FileName))
	execute "silent sp +e " . FileName
	else
		echohl error
		echo "File '" . FileName . "' not found."
		echohl normal
	endif
	execute "silent cd " . OldPath
endfunction

function! GetStringBeforeCursor()
	return strpart(getline("."), 0, col("."))
endfunction

function! GetStringAfterCursor()
	return strpart(getline("."), col("."))
endfunction

function! GetWordBeforeCursor()
	return substitute(GetStringBeforeCursor(), '^.*\(\<\w\{-1,}\)\W*$', '\1', '')
endfunction

function! GetStringBeforeWord()
	return substitute(GetStringBeforeCursor(), '^.*\(\W\{-1,}\)\<\w\{-1,}\W*$', '\1', '')
endfunction

function! GetWordBeforeParen()
	return substitute(GetStringBeforeCursor(), '^.\{-}\(\<\w\{-1,}\)\s*(.*$', '\1', '')
endfunction

function! UpcaseWordBeforeCursor()
	let Line = substitute(GetStringBeforeCursor(), '^\(.*\)\(\<\w\{-1,}\)\(\W*\)$', '\1\U\2\E\3', '')
	call setline(".", Line . GetStringAfterCursor())
endfunction

function! GetWordUnder()
	let WordBeginning = substitute(GetStringBeforeCursor(), '^.*\<\(\w\{-1,}\)$', '\1', '')
	if match(GetStringAfterCursor(), '\w') == 0
		let WordEnd = substitute(GetStringAfterCursor(), '^\<\(\w\{-1,}\)\>.*$', '\1', '')
	else
		let WordEnd = ''
	endif
	let Word = WordBeginning . WordEnd
	return Word
endfunction

function! ColonComplete()
	normal! a:
endfunction

function! ShowFileFormatFlag(var) 
	if ( a:var == 'dos' ) 
		return '[DOS]' 
	elseif ( a:var == 'mac' ) 
		return '[MAC]' 
	else 
		return '[UNIX]' 
	endif 
endfunction

function! InsertDateTime()
	execute "normal a" . strftime("%A, %Y-%m-%d %H:%M:%S")
endfunction

function! CtagAdder(...)
	let index = 1
	let s:dir_list = ''
	while index <= a:0
		let s:dir_list = s:dir_list . TlGetDirs(a:{index})
		let index = index + 1
	endwhile
	call TlAddAddFiles(s:dir_list)
	wincmd p
	exec "normal ="
	wincmd p
endfunction

" Adds *.rb, *.rhtml and *.css files to TagList from a given list
" of dirs

function! TlAddAddFiles(dir_list)
	let dirlist = a:dir_list
	let s:olddir = getcwd()
	while strlen(dirlist) > 0
		let curdir = substitute (dirlist, '|.*', "", "")
		let dirlist = substitute (dirlist, '[^|]*|\?', "", "")
		exec "cd " . g:base_dir
		exec "TlistAddFiles " . curdir . "/*.rb"
		exec "TlistAddFiles " . curdir . "/*.rhtml"
		exec "TlistAddFiles " . curdir . "/*.css"
"		exec "TlistAddFiles " . curdir . "/*.js"
	endwhile
	exec "cd " . s:olddir
endfunction

" Gets all dirs within a given dir, returns them in a string,
" separated by '|''s

function! TlGetDirs(start_dir)
	let s:olddir = getcwd()
	exec "cd " . g:base_dir . '/' . a:start_dir
	let dirlist = a:start_dir . '|'
	let dirlines = glob ('*')
	let dirlines = substitute (dirlines, "\n", '/', "g")
	while strlen(dirlines) > 0
		let curdir = substitute (dirlines, '/.*', "", "")
		let dirlines = substitute (dirlines, '[^/]*/\?', "", "")
		if isdirectory(g:base_dir . '/' . a:start_dir . '/' . curdir)
			let dirlist = dirlist . TlGetDirs(a:start_dir . '/' . curdir)
		endif
	endwhile
	exec "cd " . s:olddir
	return dirlist
endfunction

function! GuiTabLabel()
	let label = ''
	let bufnrlist = tabpagebuflist(v:lnum)

	" Add '+' if one of the buffers in the tab page is modified
	for bufnr in bufnrlist
	if getbufvar(bufnr, "&modified")
		let label = '+'
		break
	endif
	endfor

	" Append the number of windows in the tab page if more than one
	let wincount = tabpagewinnr(v:lnum, '$')
	if wincount > 1
		let label .= wincount
	endif
	if label != ''
		let label .= ' '
	endif

	" Append the buffer name
	return label . bufname(bufnrlist[tabpagewinnr(v:lnum) - 1])
endfunction
